home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / mxlibs / smixc118 / smix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-27  |  22.8 KB  |  824 lines

  1. /*      SMIXC is Copyright 1995 by Ethan Brodsky.  All rights reserved      */
  2.  
  3. /* █ smix.c v1.18 █████████████████████████████████████████████████████████ */
  4.  
  5. #define TRUE  1
  6. #define FALSE 0
  7.  
  8. #define ON  1
  9. #define OFF 0
  10.  
  11. #define BLOCK_LENGTH    256   /* Length of digitized sound output block     */
  12. #define LOAD_CHUNK_SIZE 2048  /* Chunk size used to load sounds from disk   */
  13. #define VOICES          8     /* Number of available simultaneous voices    */
  14.  
  15. typedef struct
  16.   {
  17.     int xmshandle;
  18.     long startofs;
  19.     long soundsize;
  20.   } SOUND;
  21.  
  22. int  init_sb(int baseio, int irq, int dma, int dma16);
  23.   /* Initializes control parameters, resets DSP and installs int. handler   */
  24.   /*  Parameters:                                                           */
  25.   /*   baseio    Sound card base IO address                                 */
  26.   /*   irq       Sound card IRQ setting                                     */
  27.   /*   dma       Sound card 8-bit DMA channel                               */
  28.   /*   dma16     Sound card 16-bit DMA channel                              */
  29.   /*  Returns:                                                              */
  30.   /*   TRUE      Sound card successfully initialized                        */
  31.   /*   FALSE     Sound card could not be initialized                        */
  32.  
  33. void shutdown_sb(void);
  34.   /* Removes interrupt handler and resets DSP                               */
  35.  
  36.  
  37. void init_mixing(void);
  38.   /* Allocates internal buffers and starts digitized sound output           */
  39.  
  40. void shutdown_mixing(void);
  41.   /* Deallocates internal buffers and stops digitized sound output          */
  42.  
  43.  
  44. int  init_xms(void);
  45.   /* Initializes extended memory driver                                     */
  46.   /*  Returns:                                                              */
  47.   /*   TRUE      Extended memory driver successfully initialized            */
  48.   /*   FALSE     Extended memory driver could not be initialized            */
  49.  
  50. int  getfreexms(void);
  51.   /* Returns amount of free extended memory (In kilobytes)                  */
  52.  
  53.  
  54. void init_sharing(void);
  55.   /* Allocates an EMB that all sound data will be stored in.  Using this    */
  56.   /* will preserve extended memory handles, which are scarce resources.     */
  57.   /* Call this on initialization and all sounds will automatically be       */
  58.   /* stored in one EMB.  You can call load_sound as usual to allocate a     */
  59.   /* sound, but free_sound will only deallocate the sound data structure.   */
  60.   /* You must call shutdown_sharing before program termination in order     */
  61.   /* to free all allocated extended memory.                                 */
  62.  
  63. void shutdown_sharing(void);
  64.   /* Shuts down EMB sharing and frees shared EMB block                      */
  65.  
  66.  
  67. void load_sound(SOUND **sound, char *filename);
  68.   /* Allocates an extended memory block and loads a sound from a file       */
  69.   /*  Parameters:                                                           */
  70.   /*   sound     Pointer to pointer to unallocated sound data structure     */
  71.   /*   filename  Pointer to character string containing filename            */
  72.  
  73. void free_sound(SOUND **sound);
  74.   /* Frees sound data structure and extended memory block                   */
  75.   /*  Parameters:                                                           */
  76.   /*   sound     Pointer to pointer to allocated sound data structure       */
  77.  
  78.  
  79. void start_sound(SOUND *sound, int index, int loop);
  80.   /* Starts playing a sound                                                 */
  81.   /*  Parameters:                                                           */
  82.   /*   sound     Pointer to sound data structure                            */
  83.   /*   index     A number to keep track of the sound with (Used to stop it) */
  84.   /*   loop      Indicates whether sound should be continuously looped      */
  85.  
  86. void stop_sound(int index);
  87.   /* Stops playing a sound                                                  */
  88.   /*  Parameters:                                                           */
  89.   /*   index     Index of sound to stop (All with given index are stopped)  */
  90.  
  91. int  sound_playing(int index);
  92.   /* Checks if a sound is still playing                                     */
  93.   /*  Parameters:                                                           */
  94.   /*   index     Index used when the sound was started                      */
  95.   /*  Returns:                                                              */
  96.   /*   TRUE      At least one sound with the specified index is playing     */
  97.   /*   FALSE     No sounds with the specified index are playing             */
  98.  
  99. volatile long  intcount;       /* Current count of sound interrupts         */
  100. volatile float dspversion;     /* Version of the sound card DSP chip        */
  101. volatile int   voicecount;     /* Number of voices currently in use         */
  102.  
  103. int autoinit;
  104. int sixteenbit;
  105.  
  106. /* ████████████████████████████████████████████████████████████████████████ */
  107.  
  108. #include <alloc.h>
  109. #include <conio.h>
  110. #include <stdio.h>
  111. #include <stdlib.h>
  112. #include <dos.h>
  113. #include <mem.h>
  114.  
  115. #include "xms.h"
  116.  
  117. #define BUFFER_LENGTH BLOCK_LENGTH*2
  118.  
  119. #define BYTE unsigned char
  120.  
  121. #define lo(value) (unsigned char)((value) & 0x00FF)
  122. #define hi(value) (unsigned char)((value) >> 8)
  123.  
  124. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  125. #define MIN(a, b) (((a) > (b)) ? (b) : (a))
  126.  
  127. int resetport;
  128. int readport;
  129. int writeport;
  130. int pollport;
  131. int ackport;
  132.  
  133. int pic_rotateport;
  134. int pic_maskport;
  135.  
  136. int dma_maskport;
  137. int dma_clrptrport;
  138. int dma_modeport;
  139. int dma_addrport;
  140. int dma_countport;
  141. int dma_pageport;
  142.  
  143. int irq_startmask;
  144. int irq_stopmask;
  145. int irq_intvector;
  146.  
  147. int dma_startmask;
  148. int dma_stopmask;
  149. int dma_mode;
  150. int dma_length;
  151.  
  152. int  shared_emb     = FALSE;
  153. int  shared_handle  = 0;
  154. long shared_size    = 0;
  155.  
  156. void (interrupt far *oldintvector)(void);
  157.  
  158. int handler_installed = FALSE;
  159.  
  160. void write_dsp(BYTE value)
  161.   {
  162.     while ((inp(writeport) & 0x80));
  163.     outp(writeport, value);
  164.   }
  165.  
  166. BYTE read_dsp(void)
  167.   {
  168.     while (!(inp(pollport) & 0x80));
  169.     return(inp(readport));
  170.   }
  171.  
  172. int reset_dsp(void)
  173.   {
  174.     int i;
  175.  
  176.     outp(resetport, 1);
  177.     delay(1);                            /* 1 millisecond */
  178.     outp(resetport, 0);
  179.  
  180.     i = 100;
  181.     while ((i-- > 0) && (read_dsp() != 0xAA));
  182.  
  183.     return(i > 0);
  184.   }
  185.  
  186. void install_handler(void);
  187. void uninstall_handler(void);
  188. void mix_exitproc(void);
  189.  
  190. int init_sb(int baseio, int irq, int dma, int dma16)
  191.   {
  192.    /* Sound card IO ports */
  193.     resetport  = baseio + 0x006;
  194.     readport   = baseio + 0x00A;
  195.     writeport  = baseio + 0x00C;
  196.     pollport   = baseio + 0x00E;
  197.  
  198.    /* Reset DSP, get version, choose output mode */
  199.     if (!reset_dsp())
  200.       return(FALSE);
  201.     write_dsp(0xE1);  /* Get DSP version number */
  202.     dspversion = read_dsp();  dspversion += read_dsp() / 100.0;
  203.     autoinit   = (dspversion > 2.0);
  204.     sixteenbit = (dspversion > 4.0) && (dma16 != 0);
  205.  
  206.    /* Compute interrupt controller ports and parameters */
  207.     if (irq < 8)
  208.       { /* PIC1 */
  209.         irq_intvector  = 0x08 + irq;
  210.         pic_rotateport = 0x20;
  211.         pic_maskport   = 0x21;
  212.       }
  213.     else
  214.       { /* PIC2 */
  215.         irq_intvector  = 0x70 + irq-8;
  216.         pic_rotateport = 0xA0;
  217.         pic_maskport   = 0xA1;
  218.       }
  219.     irq_stopmask  = 1 << (irq % 8);
  220.     irq_startmask = ~irq_stopmask;
  221.  
  222.    /* Compute DMA controller ports and parameters */
  223.     if (sixteenbit)
  224.       { /* Sixteen bit */
  225.         dma_maskport   = 0xD4;
  226.         dma_clrptrport = 0xD8;
  227.         dma_modeport   = 0xD6;
  228.         dma_addrport   = 0xC0 + 4*(dma16-4);
  229.         dma_countport  = 0xC2 + 4*(dma16-4);
  230.         switch (dma16)
  231.           {
  232.             case 5:
  233.               dma_pageport = 0x8B;
  234.               break;
  235.             case 6:
  236.               dma_pageport = 0x89;
  237.               break;
  238.             case 7:
  239.               dma_pageport = 0x8A;
  240.               break;
  241.           }
  242.         dma_stopmask  = dma16-4 + 0x04;  /* 000001xx */
  243.         dma_startmask = dma16-4 + 0x00;  /* 000000xx */
  244.         if (autoinit)
  245.           dma_mode = dma16-4 + 0x58;     /* 010110xx */
  246.         else
  247.           dma_mode = dma16-4 + 0x48;     /* 010010xx */
  248.         ackport = baseio + 0x00F;
  249.       }
  250.     else
  251.       { /* Eight bit */
  252.         dma_maskport   = 0x0A;
  253.         dma_clrptrport = 0x0C;
  254.         dma_modeport   = 0x0B;
  255.         dma_addrport   = 0x00 + 2*dma;
  256.         dma_countport  = 0x01 + 2*dma;
  257.         switch (dma)
  258.           {
  259.             case 0:
  260.               dma_pageport = 0x87;
  261.               break;
  262.             case 1:
  263.               dma_pageport = 0x83;
  264.               break;
  265.             case 2:
  266.               dma_pageport = 0x81;
  267.               break;
  268.             case 3:
  269.               dma_pageport = 0x82;
  270.               break;
  271.           }
  272.         dma_stopmask  = dma + 0x04;      /* 000001xx */
  273.         dma_startmask = dma + 0x00;      /* 000000xx */
  274.         if (autoinit)
  275.           dma_mode    = dma + 0x58;      /* 010110xx */
  276.         else
  277.           dma_mode    = dma + 0x48;      /* 010010xx */
  278.         ackport = baseio + 0x00E;
  279.       }
  280.     if (autoinit)
  281.       dma_length = BUFFER_LENGTH;
  282.     else
  283.       dma_length = BLOCK_LENGTH;
  284.  
  285.     install_handler();
  286.     atexit(mix_exitproc);
  287.  
  288.     return(TRUE);
  289.   }
  290.  
  291. void shutdown_sb(void)
  292.   {
  293.     if (handler_installed) uninstall_handler();
  294.     reset_dsp();
  295.   }
  296.  
  297. int init_xms(void)
  298.   {
  299.     xms_init();
  300.     return(xms_installed());
  301.   }
  302.  
  303. int getfreexms(void)
  304.   {
  305.     return(xms_getfreemem());
  306.   }
  307.  
  308. /* Voice control */
  309. typedef struct
  310.   {
  311.     SOUND *sound;
  312.     int   index;
  313.     long  curpos;
  314.     int   loop;
  315.   } VOICE;
  316.  
  317. int   inuse[VOICES];
  318. VOICE voice[VOICES];
  319.  
  320. /* Sound buffer */
  321.  
  322. signed char soundblock[BLOCK_LENGTH+1]; /* Signed 8 bit */
  323.   /* The length of XMS copies under HIMEM.SYS must be a mutiple  */
  324.   /* of two.  If the sound data ends in mid-block, it may not be */
  325.   /* possible to round up without corrupting memory.  Therefore, */
  326.   /* the copy buffer has been extended by one byte to eliminate  */
  327.   /* this problem.                                               */
  328.  
  329. /* Mixing buffer */
  330.  
  331. short int mixingblock[BLOCK_LENGTH];    /* Signed 16 bit */
  332.  
  333. /* Output buffers */
  334.  
  335. void *outmemarea = NULL;
  336. unsigned char (*out8buf)[2][BLOCK_LENGTH]  = NULL;  /* Unsigned 8 bit */
  337. short int     (*out16buf)[2][BLOCK_LENGTH] = NULL;  /* Signed 16 bit  */
  338.  
  339. int curblock;
  340. void *blockptr[2];
  341. void *curblockptr;
  342.  
  343. /* Addressing for auto-initialized transfers (Whole buffer) */
  344. unsigned long buffer_addr;
  345. unsigned char buffer_page;
  346. unsigned int  buffer_ofs;
  347.  
  348. /* Addressing for single-cycle transfers (One block at a time */
  349. unsigned long block_addr[2];
  350. unsigned char block_page[2];
  351. unsigned int  block_ofs[2];
  352.  
  353. int handler_installed;
  354.  
  355. /* 8-bit clipping */
  356.  
  357. unsigned char *clip_8_buf;  /* Pointer to clipping array           */
  358. unsigned char *clip_8;      /* Pointer to center of clipping array */
  359.  
  360. void start_dac(void)
  361.   {
  362.     outp(dma_maskport,   dma_stopmask);
  363.     outp(dma_clrptrport, 0x00);
  364.     outp(dma_modeport,   dma_mode);
  365.     outp(dma_addrport,   lo(buffer_ofs));
  366.     outp(dma_addrport,   hi(buffer_ofs));
  367.     outp(dma_countport,  lo(dma_length-1));
  368.     outp(dma_countport,  hi(dma_length-1));
  369.     outp(dma_pageport,   buffer_page);
  370.     outp(dma_maskport,   dma_startmask);
  371.  
  372.     if (sixteenbit)
  373.       { /* Sixteen bit auto-initialized: SB16 and up (DSP 4.xx)             */
  374.         write_dsp(0x41);                /* Set sound output sampling rate   */
  375.         write_dsp(hi(22050));
  376.         write_dsp(lo(22050));
  377.         write_dsp(0xB6);                /* 16-bit cmd  - D/A - A/I - FIFO   */
  378.         write_dsp(0x10);                /* 16-bit mode - signed mono        */
  379.         write_dsp(lo(BLOCK_LENGTH-1));
  380.         write_dsp(hi(BLOCK_LENGTH-1));
  381.       }
  382.     else
  383.       { /* Eight bit */
  384.         write_dsp(0xD1);                /* Turn on speaker                  */
  385.         write_dsp(0x40);                /* Set sound output time constant   */
  386.         write_dsp(211);                 /*  = 256 - (1000000 / rate)        */
  387.         if (autoinit)
  388.           { /* Eight bit auto-initialized:  SBPro and up (DSP 2.00+)        */
  389.             write_dsp(0x48);            /* Set DSP block transfer size      */
  390.             write_dsp(lo(BLOCK_LENGTH-1));
  391.             write_dsp(hi(BLOCK_LENGTH-1));
  392.             write_dsp(0x1C);            /* 8-bit auto-init DMA mono output  */
  393.           }
  394.         else
  395.           { /* Eight bit single-cycle:  Sound Blaster (DSP 1.xx+)           */
  396.             write_dsp(0x14);            /* 8-bit single-cycle DMA output    */
  397.             write_dsp(lo(BLOCK_LENGTH-1));
  398.             write_dsp(hi(BLOCK_LENGTH-1));
  399.           }
  400.       }
  401.   }
  402.  
  403. void stop_dac(void)
  404.   {
  405.     if (sixteenbit)
  406.       {
  407.         write_dsp(0xD5);                /* Pause 16-bit DMA sound I/O       */
  408.       }
  409.     else
  410.       {
  411.         write_dsp(0xD0);                /* Pause 8-bit DMA sound I/O        */
  412.         write_dsp(0xD3);                /* Turn off speaker                 */
  413.       }
  414.     outp(dma_maskport, dma_stopmask);
  415.   }
  416.  
  417.  
  418. /* Setup for storinng all sounds in one EMB (Saves handles) */
  419.  
  420. void init_sharing(void)
  421.   {
  422.     shared_emb = TRUE;
  423.     xms_allocate(&shared_handle, (shared_size = 0));
  424.   }
  425.  
  426. void shutdown_sharing(void)
  427.   {
  428.     if (shared_emb) xms_free(&shared_handle);
  429.     shared_emb    = FALSE;
  430.     shared_handle = 0;
  431.     shared_size   = 0;
  432.   }
  433.  
  434. /* Loading and freeing sounds */
  435.  
  436. void load_sound(SOUND **sound, char *filename)
  437.   {
  438.     FILE *f;
  439.     long size;
  440.     char inbuf[LOAD_CHUNK_SIZE];
  441.     static MOVEPARAMS moveparams;
  442.  
  443.     f = fopen(filename, "rb");
  444.     fseek(f, 0, SEEK_END); /* Move to end of file */
  445.     size = ftell(f);       /* File size = end pos */
  446.     fseek(f, 0, SEEK_SET); /* Back to begining    */
  447.  
  448.     *sound = (SOUND *)malloc(sizeof(SOUND));
  449.  
  450.     (*sound)->soundsize = size;
  451.  
  452.     if (!shared_emb)
  453.       {
  454.         (*sound)->startofs = 0;
  455.         xms_allocate(&((*sound)->xmshandle), (size + 1023) / 1024);
  456.       }
  457.     else
  458.       {
  459.         (*sound)->startofs  = shared_size;
  460.         (*sound)->xmshandle = shared_handle;
  461.         shared_size += size;
  462.         xms_reallocate(shared_handle, (shared_size + 1023) / 1024);
  463.       }
  464.  
  465.     moveparams.sourcehandle = 0;
  466.     moveparams.sourceoffset = (long)(&inbuf);
  467.     moveparams.desthandle   = (*sound)->xmshandle;
  468.     moveparams.destoffset   = (*sound)->startofs;
  469.  
  470.     do
  471.       {
  472.         moveparams.length = fread(&inbuf, 1, sizeof(inbuf), f);
  473.         moveparams.length = ((moveparams.length+1) / 2) * 2;
  474.           /* XMS copy lengths must be a multiple of two */
  475.         xms_move(&moveparams);
  476.         moveparams.destoffset += moveparams.length;
  477.       }
  478.     while (moveparams.length != 0);
  479.  
  480.     fclose(f);
  481.   }
  482.  
  483. void free_sound(SOUND **sound)
  484.   {
  485.     if (!shared_emb) xms_free(&((*sound)->xmshandle));
  486.     free(*sound);
  487.     *sound = NULL;
  488.   }
  489.  
  490. /* Voice maintainance */
  491.  
  492. void deallocate_voice(int voicenum)
  493.   {
  494.     inuse[voicenum] = FALSE;
  495.     voice[voicenum].sound  = NULL;
  496.     voice[voicenum].index  = 0;
  497.     voice[voicenum].curpos = 0;
  498.     voice[voicenum].loop   = 0;
  499.   }
  500.  
  501. void start_sound(SOUND *sound, int index, int loop)
  502.   {
  503.     int i, slot;
  504.     slot = -1; i = 0;
  505.     do
  506.       {
  507.         if (!inuse[i])
  508.           slot = i;
  509.         i++;
  510.       }
  511.     while ((slot == -1) && (i < VOICES));
  512.     if (slot != -1)
  513.       {
  514.         voice[slot].sound  = sound;
  515.         voice[slot].index  = index;
  516.         voice[slot].curpos = 0;
  517.         voice[slot].loop   = loop;
  518.  
  519.         ++voicecount;
  520.         inuse[slot] = TRUE;
  521.       }
  522.   }
  523.  
  524. void stop_sound(int index)
  525.   {
  526.     int i;
  527.     for (i=0; i < VOICES; i++)
  528.       if (voice[i].index == index)
  529.         {
  530.           deallocate_voice(i);
  531.           --voicecount;
  532.         }
  533.   }
  534.  
  535. int  sound_playing(int index)
  536.   {
  537.     int i;
  538.  
  539.    /* Search for a sound with the specified index */
  540.     for (i=0; i < VOICES; i++)
  541.       if (voice[i].index == index)
  542.         return(TRUE);
  543.  
  544.    /* Sound not found */
  545.     return(FALSE);
  546.   }
  547.  
  548. void update_voices(void)
  549.   {
  550.     int voicenum;
  551.  
  552.     for (voicenum=0; voicenum < VOICES; voicenum++)
  553.       {
  554.         if (inuse[voicenum])
  555.           {
  556.             if (voice[voicenum].curpos >= voice[voicenum].sound->soundsize)
  557.               {
  558.                 deallocate_voice(voicenum);
  559.                 --voicecount;
  560.               }
  561.           }
  562.       }
  563.   }
  564.  
  565. /* Utility functions */
  566.  
  567. void setcurblock(int blocknum)
  568.   {
  569.     curblockptr = blockptr[(curblock = blocknum)];
  570.   }
  571.  
  572. void silenceblock(void)
  573.   {
  574.     memset(&mixingblock, 0x00, BLOCK_LENGTH*2);
  575.   }
  576.  
  577. long getlinearaddr(void far *ptr)
  578.   {
  579.     return((long)FP_SEG(ptr)*16 + (long)FP_OFF(ptr));
  580.   }
  581.  
  582. /* Mixing initialization */
  583.  
  584. void init_clip8(void)
  585.   {
  586.     int i;
  587.     int value;
  588.  
  589.     clip_8_buf = malloc(256*VOICES);
  590.     clip_8     = clip_8_buf + 128*VOICES;
  591.  
  592.     for (i = -128*VOICES; i < 128*VOICES; i++)
  593.       {
  594.         value = i;
  595.         value = max(value, -128);
  596.         value = min(value, 127);
  597.  
  598.         clip_8[i] = value + 128;
  599.       }
  600.   }
  601.  
  602. void init_mixing(void)
  603.   {
  604.     int i;
  605.  
  606.     for (i=0; i < VOICES; i++)
  607.       deallocate_voice(i);
  608.     voicecount = 0;
  609.  
  610.     if (sixteenbit)
  611.       {
  612.        /* Find a block of memory that does not cross a page boundary */
  613.         outmemarea = malloc(4*BUFFER_LENGTH);
  614.         out16buf = outmemarea;
  615.         if ((((getlinearaddr(outmemarea) >> 1) % 65536) + BUFFER_LENGTH) > 65536)
  616.           out16buf += BUFFER_LENGTH;
  617.         for (i=0; i<2; i++) blockptr[i] = (void *)&((*out16buf)[i]);
  618.  
  619.        /* DMA parameters */
  620.         buffer_addr = getlinearaddr(out16buf);
  621.         buffer_page = buffer_addr >> 16;
  622.         buffer_ofs  = (buffer_addr >> 1) % 65536;
  623.  
  624.         memset((void *)out16buf, 0x00, BUFFER_LENGTH*2);  /* Signed 16-bit  */
  625.       }
  626.     else
  627.       {
  628.        /* Find a block of memory that does not cross a page boundary */
  629.         outmemarea = malloc(2*BUFFER_LENGTH);
  630.         out8buf = outmemarea;
  631.         if (((getlinearaddr(outmemarea) % 65536) + BUFFER_LENGTH) > 65536)
  632.           out8buf += BUFFER_LENGTH;
  633.         for (i=0; i<2; i++) blockptr[i] = (void *)&((*out8buf)[i]);
  634.  
  635.        /* DMA parameters */
  636.         buffer_addr = getlinearaddr(out8buf);
  637.         buffer_page = buffer_addr / 65536;
  638.         buffer_ofs  = buffer_addr % 65536;
  639.         for (i=0; i<2; i++)
  640.           {
  641.             block_addr[i] = getlinearaddr(blockptr[i]);
  642.             block_page[i] = block_addr[i] / 65536;
  643.             block_ofs[i]  = block_addr[i]  % 65536;
  644.           }
  645.         memset((void *)out8buf, 0x80, BUFFER_LENGTH);    /* Unsigned 8-bit */
  646.  
  647.         init_clip8();
  648.       }
  649.  
  650.     setcurblock(0);
  651.     intcount = 0;
  652.     start_dac();
  653.   }
  654.  
  655. void shutdown_mixing(void)
  656.   {
  657.     stop_dac();
  658.  
  659.     if (!sixteenbit) free(clip_8_buf);
  660.  
  661.     free((void *)outmemarea);
  662.   }
  663.  
  664. void copy_sound(SOUND *sound, long *curpos, int copylength, int loop)
  665.   {
  666.     long soundsize;
  667.     char far *destptr;
  668.     static MOVEPARAMS moveparams;
  669.  
  670.     soundsize = sound->soundsize;
  671.     destptr   = (char far *)(&soundblock);
  672.     moveparams.sourcehandle = sound->xmshandle;
  673.     moveparams.desthandle   = 0;
  674.     do
  675.       {
  676.        /* Compute transfer size */
  677.         moveparams.length = min(copylength, soundsize - (*curpos));
  678.  
  679.        /* Compute starting source offset and update offset for next block */
  680.         moveparams.sourceoffset = sound->startofs + (*curpos);
  681.         (*curpos) += moveparams.length;
  682.         if (loop) (*curpos) %= soundsize;
  683.  
  684.        /* Compute starting dest offset and update offset for next block */
  685.         moveparams.destoffset = (long)destptr;
  686.         destptr += moveparams.length;
  687.  
  688.        /* Update remaining count for next iteration (If any) */
  689.         copylength -= moveparams.length;
  690.  
  691.        /* Copy block down from extended memory */
  692.         moveparams.length = ((moveparams.length + 1) / 2) * 2;
  693.           /* XMS copy lengths must be a multiple of two */
  694.         xms_move(&moveparams);  /* Luckily, the XMS driver is re-entrant */
  695.       }
  696.     while (copylength > 0);
  697.   }
  698.  
  699. void mix_voice(VOICE *voice)
  700.   {
  701.     int i;
  702.  
  703.     int mixlength;
  704.  
  705.     if (voice->loop)
  706.       mixlength = BLOCK_LENGTH;
  707.     else
  708.       mixlength = MIN(BLOCK_LENGTH, voice->sound->soundsize - voice->curpos);
  709.     copy_sound(voice->sound, &(voice->curpos), mixlength, voice->loop);
  710.  
  711.     for (i=0; i < BLOCK_LENGTH; i++)
  712.       mixingblock[i] += soundblock[i];
  713.   }
  714.  
  715. void mix_voices(void)
  716.   {
  717.     int i;
  718.  
  719.     silenceblock();
  720.     for (i=0; i < VOICES; i++)
  721.       if (inuse[i]) mix_voice(&(voice[i]));
  722.   }
  723.  
  724. void copy_sound16(void)
  725.   {
  726.     int i;
  727.     signed int *destptr;
  728.  
  729.     destptr   = blockptr[curblock];
  730.  
  731.     for (i=0; i < BLOCK_LENGTH; i++)
  732.       destptr[i] = mixingblock[i] << 5;
  733.   }
  734.  
  735. void copy_sound8(void)
  736.   {
  737.     unsigned char *outptr;
  738.     int i;
  739.  
  740.     outptr = &((*out8buf)[curblock][0]);
  741.     for (i=0; i < BLOCK_LENGTH; i++)
  742.       *outptr++ = clip_8[mixingblock[i]];
  743.   }
  744.  
  745. void copydata(void)
  746.   {
  747.     if (sixteenbit)
  748.       copy_sound16();
  749.     else
  750.       copy_sound8();
  751.   }
  752.  
  753. void startblock_sc(void) /* Starts a single-cycle DMA transfer */
  754.   {
  755.     outp(dma_maskport,   dma_stopmask);
  756.     outp(dma_clrptrport, 0x00);
  757.     outp(dma_modeport,   dma_mode);
  758.     outp(dma_addrport,   lo(block_ofs[curblock]));
  759.     outp(dma_addrport,   hi(block_ofs[curblock]));
  760.     outp(dma_countport,  lo(BLOCK_LENGTH-1));
  761.     outp(dma_countport,  hi(BLOCK_LENGTH-1));
  762.     outp(dma_pageport,   block_page[curblock]);
  763.     outp(dma_maskport,   dma_startmask);
  764.     write_dsp(0x14);                /* 8-bit single-cycle DMA sound output  */
  765.     write_dsp(lo(BLOCK_LENGTH-1));
  766.     write_dsp(hi(BLOCK_LENGTH-1));
  767.   }
  768.  
  769. void interrupt inthandler(void)
  770.   {
  771.     intcount++;
  772.     if (!autoinit)  /* Start next block first if not using auto-init DMA */
  773.       {
  774.         startblock_sc();
  775.         copydata();
  776.         setcurblock(!curblock); /* Toggle block */
  777.       }
  778.  
  779.     update_voices();
  780.     mix_voices();
  781.  
  782.     if (autoinit)
  783.       {
  784.         copydata();
  785.         setcurblock(!curblock); /* Toggle block */
  786.       }
  787.  
  788.     inp(ackport);      /* Acknowledge interrupt with sound card */
  789.     outp(0xA0, 0x20);  /* Acknowledge interrupt with PIC2 */
  790.     outp(0x20, 0x20);  /* Acknowledge interrupt with PIC1 */
  791.   }
  792.  
  793. void install_handler(void)
  794.   {
  795.     disable();
  796.     outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  797.  
  798.     oldintvector = _dos_getvect(irq_intvector);
  799.     _dos_setvect(irq_intvector, inthandler);
  800.  
  801.     outp(pic_maskport, (inp(pic_maskport) & irq_startmask));
  802.     enable();
  803.  
  804.     handler_installed = TRUE;
  805.   }
  806.  
  807. void uninstall_handler(void)
  808.   {
  809.       disable();
  810.       outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  811.  
  812.       _dos_setvect(irq_intvector, oldintvector);
  813.  
  814.       enable();
  815.  
  816.       handler_installed = FALSE;
  817.   }
  818.  
  819. void mix_exitproc(void)
  820.   {
  821.     stop_dac();
  822.     shutdown_sb();
  823.   }
  824.